home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / SED15.ARJ / SEDEXEC.C < prev    next >
C/C++ Source or Header  |  1991-09-27  |  20KB  |  539 lines

  1. /*
  2.  * sedexec.c -- execute compiled form of stream editor commands
  3.  *
  4.  * The single entry point of this module is the function execute(). It may take
  5.  * a string argument (the name of a file to be used as text)  or the argument
  6.  * NULL which tells it to filter standard input. It executes the compiled
  7.  * commands in cmds[] on each line in turn. The function command() does most
  8.  * of the work. Match() and advance() are used for matching text against
  9.  * precompiled regular expressions and dosub() does right-hand-side
  10.  * substitution.  Getline() does text input; readout() and smemcmp() are
  11.  * output and string-comparison utilities.
  12.  *
  13.  * ==== Written for the GNU operating system by Eric S. Raymond ====
  14.  * v1.2, 14 Jul 91
  15.  * From: mdlawler@bsu-cs.bsu.edu (Michael D. Lawler)
  16.  * Change the line in sedexec.c from
  17.  *    static int delete;
  18.  * to
  19.  *   static int delete = TRUE;
  20.  * and let me know if it still compiles ok under TurboC 2.0.
  21.  * I made this change which was suggested by Mark Adler
  22.  * and it made sed work fine under BC++ 2.0.
  23.  *
  24.  * Toad Hall:  Compiles just fine in TC 2.0.
  25.  *
  26.  * v1.1, 19 Jun 91
  27.  * Toad Hall Tweak for TC v2.0
  28.  * See VERSION.NOT for details
  29.  * modified September 91 by hh see notes in sedcomp.c
  30.  */
  31.  
  32. #ifdef OTHER /*hh 14*/
  33. #include "compiler.h"
  34. #include "debug.h"
  35. #endif
  36. #ifdef LATTICE
  37. #define void int
  38. #endif
  39.  
  40. #include <stdio.h>    /* {f}puts, {f}printf, getc/putc, f{re}open, fclose */
  41. #include <ctype.h>    /* for isprint(), isdigit(), toascii() macros */
  42. #include "sed.h"    /* command type structures & miscellaneous* constants */
  43.  
  44. #ifdef __TURBOC__        /* v1.1 */
  45. #include <string.h>
  46. #include <stdlib.h>        /* exit() */
  47. static char    *getline(register char *buf);
  48. static int    selected(sedcmd *ipc);
  49. static void    command(sedcmd *ipc);
  50. static void     readout(void);
  51. static int    match(char *expbuf, int gf);
  52. static int    advance(register char *lp, register char *ep);
  53. static void    dosub(char *rhsbuf);
  54. static char    *place(char *asp,char *al1,char *al2);
  55. static void    listto(register char *p1, FILE *fp);
  56. static int    substitute(sedcmd *ipc);
  57. /* v1.1 renamed this so it wouldn't conflict with TC's memcmp() */
  58. static int    smemcmp(register char *a, register char *b, int count);
  59. #else    /* !PROTO */
  60. extern char    *strcpy();    /* used in dosub */
  61.     char    *getline();    /* input-getting functions */
  62.     void    command(), readout();
  63.     void    dosub();    /* for if we find a match */
  64.     char            *place();
  65. #endif    /* ?PROTO */
  66.  
  67. /***** shared variables imported from the main ******/
  68.  
  69. /* main data areas */
  70. extern char    linebuf[];    /* current-line buffer */
  71. extern sedcmd    cmds[];        /* hold compiled commands */
  72. extern long    linenum[];    /* numeric-addresses table */
  73.  
  74. /* miscellaneous shared variables */
  75. extern int    nflag;        /* -n option flag */
  76. extern int    eargc;        /* scratch copy of argument count */
  77. extern sedcmd    *pending;    /* ptr to command waiting to be executed */
  78. extern char    bits[];        /* the bits table */
  79.  
  80. #define MAXHOLD        MAXBUF    /* size of the hold space */
  81. #define GENSIZ        MAXBUF    /* maximum genbuf size */
  82. #define TRUE            1
  83. #define FALSE            0
  84. #define JUMPLIMIT  50  /*max branches before inf loop*/
  85. #define ABORT2(msg,arg) (fprintf(stderr,msg,arg),exit(2))
  86. #define ISWCHAR(c) (isalnum(c)||c=='_')
  87. #define Copy(to,from,ep) {char *it=to,*ix=from;while(*it++=*ix++);ep=it-1;}
  88. static char     INFLOOP[]= "sed: infinite branch loop at line %ld\n";
  89. static char    LTLMSG[] = "sed: line too long at line %ld\n";
  90. static char     FILEBAD[]= "sed: cannot open %s\n";
  91. static char     REBAD[]=   "sed: RE bad code %x\n";
  92. static char     APPERR[]=  "sed: too many appends after line %ld\n";
  93. static char     APPLNG[]=  "sed: append too long after line %ld\n";
  94. static char     READERR[]= "sed: too many reads after line %ld\n";
  95. static char    *spend;        /* current end-of-line-buffer pointer */
  96. static long    lnum = 0L;    /* current source line number */
  97.  
  98. /* append buffer maintenance */
  99. static sedcmd  *appends[MAXAPPENDS];    /* array of ptrs to a,i,c commands */
  100. static sedcmd **aptr = appends;            /* ptr to current append */
  101.  
  102. /* genbuf and its pointers and misc pointers*/
  103. static char    genbuf[GENSIZ];
  104. static long     pcnt[MAXPLUS]; /*holder for count downs*/
  105.  
  106. /* command-logic flags */
  107. static int    lastline;    /* do-line flag */
  108. static int    jump, jumpcnt;    /* jump set and loop counter */
  109. static int    delete = FALSE;    /* delete command flag *//*hh 2*/
  110. static int      cdswitch=FALSE; /*in midst of D command*/
  111.  
  112. /* tagged-pattern tracking */
  113. static char    *bracend[MAXTAGS+1];    /* tagged pattern start pointers */
  114. static char    *brastart[MAXTAGS+1];    /* tagged pattern end pointers */
  115.  
  116. /* execute the compiled commands in cmds[] on a file */
  117. void execute(file) char    *file;{    /* name of text source file to be edited */
  118.     register sedcmd *ipc;    /* ptr to current command */
  119.     if (file&&!freopen(file, "rt", stdin)) ABORT2(FILEBAD,file);
  120.     /* here's the main command-execution loop */
  121.         while(pending||cdswitch||(spend=getline(linebuf))){  /* v1.5*/
  122.         ipc =pending? pending:cmds;
  123.         delete=jumpcnt=0;cdswitch=FALSE;
  124.         while(!delete&&ipc->command){
  125.            if(pending||selected(ipc))command(ipc);
  126.            if(jump){
  127.             jump=FALSE;
  128.             if(++jumpcnt>=JUMPLIMIT)ABORT2(INFLOOP,lnum);
  129.             ipc=ipc->u.link;}
  130.            else ipc++;}
  131.         if(pending)break;
  132.         /* we've now done all modification commands on the line */
  133.         PASS("execute(): output");
  134.         if (!nflag && !delete)  puts(linebuf);
  135.         /* if we've been set up for append, emit the text from it */
  136.         if (aptr > appends)readout();
  137.         PASS("execute(): end main loop");}
  138.     PASS("execute(): end execute");}
  139.  
  140. static int selected(ipc)
  141. sedcmd *ipc;
  142. /* is current command selected */
  143. {/*hh 10*/
  144.    char  *p1=ipc->addr1;
  145.    char  *p2=ipc->addr2;
  146.    int ans,first=FALSE;
  147.  
  148.    if(!p1)return !ipc->flags.allbut;
  149.    if( (ans=ipc->flags.inrange) != 0) ;    /* v1.4 */
  150.    else if (*p1 == CEND) ans=lastline;
  151.    else if (*p1==CLNUM)
  152.         first=ipc->flags.inrange=ans=lnum==linenum[*(unsigned char*)(p1+1)];
  153.    else first=ipc->flags.inrange=ans=match(p1, 0);
  154.    if ( ((ipc->flags.inrange&=(p2!=0)) != 0)
  155.         && (*p2!=CEND)
  156.       ) {
  157.       if(*p2==CLNUM)ipc->flags.inrange=(lnum<linenum[*(unsigned char*)(p2+1)]);
  158.       else if(*p2==CPLUS){
  159.       if(first) pcnt[p2[2]]=linenum[*(unsigned char*)(p2+1)];
  160.       ipc->flags.inrange=((--pcnt[p2[2]])>=0);}
  161.       else ipc->flags.inrange=!match(p2, 0);}
  162.    return ans^ipc->flags.allbut;}
  163.  
  164. /* match RE at expbuf against linebuf; if gf set, copy linebuf from genbuf */
  165. static int match(expbuf, gf)  char *expbuf;int gf;{/* gf set on recall */
  166.     char  c,  *p1=gf?bracend[0]:linebuf; int i;
  167.         for (i=1;i<MAXTAGS+1;i++)brastart[i]=bracend[i]=linebuf;
  168.     if(gf&&*expbuf) return FALSE; /*no repeats on anchored match*/
  169.     if (*expbuf++) {
  170.         brastart[0]= p1;
  171.         if (*expbuf==CCHR &&expbuf[1] != *p1) /* 1st char is wrong */
  172.             return (FALSE);        /* so fail */
  173.         return (advance(p1, expbuf));}    /* else try to match rest */
  174.     /* quick check for 1st character if it's literal */
  175.     if (*expbuf==CCHR) {c = expbuf[1];  /* get search character */
  176.         do { if (*p1 != c)continue;    /* scan the source string */
  177.              if (advance(brastart[0]=p1,expbuf)) /* match the rest */
  178.             return  1;
  179.             } while (*p1++);
  180.         return (FALSE);}    /* didn't find that first char */
  181.     /* else try for unanchored match of the pattern */
  182.     do {if (advance(brastart[0]=p1,expbuf))return  1;
  183.         } while (*p1++);
  184.     /* if got here, didn't match either way */
  185.     return (FALSE);}
  186.  
  187. /* attempt to advance match pointer by one pattern element */
  188. static int advance(lp, ep)  char *lp, *ep; {/* source, RE*/
  189.     char  *curlp;    /* save ptr for closures */
  190.     char   c;    /* scratch character holder */
  191.     char  *bbeg,*tep;
  192.     int    ct,i1,i2;    /* scratch integer holders */
  193.     while((c=*ep++)!=CEOF) switch(c){
  194.       case CCHR:            /* literal character */
  195.         if (*ep++ == *lp++) break;    /* if chars are equal */
  196.         return (FALSE);            /* else return false */
  197.       case CBOW:                    /*at the begining of a word*/
  198.            if(ISWCHAR(*lp)&&!ISWCHAR(lp[-1]))break; /*at word start*/
  199.            return (FALSE);
  200.       case CEOW:                    /*at the end of a word*/
  201.            if(!ISWCHAR(*lp)&&ISWCHAR(lp[-1])) break;
  202.            return (FALSE);
  203.       case CDOT:            /* anything but eol */
  204.         if (*lp++)  break;    /* not first NUL is at EOL */
  205.         return (FALSE);        /* else return false */
  206.       case CDOL:            /* end-of-line */
  207.         if (*lp == 0)  break;    /* found that  NUL? */
  208.         return (FALSE);        /* else return false */
  209.       case CCL:                /* a set */
  210.         ct = *lp++ &0xff;
  211.         if (ep[ct>>3] & bits[ct & 07]) {/* is char in set? */
  212.             ep += 32;        /* then skip rest of bitmask */
  213.             break;}            /* and keep going */
  214.         return (FALSE);            /* else return false */
  215.       case CBRA:                /* start of tagged pattern */
  216.         brastart[*ep++] = lp;    /* mark it */
  217.         break;                /* and go */
  218.       case CKET:                /* end of tagged pattern */
  219.         bracend[*ep++] = lp;    /* mark it */
  220.         break;            /* and go */
  221.       case CBACK:
  222.         bbeg = brastart[*ep];
  223.         ct = bracend[*ep++] - bbeg;
  224.         if (smemcmp(bbeg, lp, ct)) {lp += ct;break;}
  225.         return (FALSE);
  226.       case CBACK | STAR:
  227.         bbeg = brastart[*ep];
  228.         ct = bracend[*ep++] - bbeg;
  229.         curlp = lp;
  230.         while (smemcmp(bbeg, lp, ct)) lp += ct;
  231.         while (lp >= curlp) {
  232.             if (advance(lp, ep))return (TRUE);
  233.             lp -= ct;}
  234.         return (FALSE);
  235.     case CBACK|MTYPE:
  236.         bbeg = brastart[*ep];
  237.         ct = bracend[*ep++] - bbeg;
  238.         i1=*ep++&0xFF,i2=*ep++&0xFF;
  239.         while(smemcmp(bbeg,lp,ct)&&i1)lp+=ct,i1--;
  240.         if(i1)return FALSE;
  241.         if(!i2||!lp[-1]) break;
  242.         if(i2==0xFF)i2=MAXBUF;
  243.         curlp=lp;
  244.         while(smemcmp(bbeg,lp,ct)&&i2)lp+=ct,i2--;
  245.         while (lp >= curlp) {
  246.             if (advance(lp, ep))return (TRUE);
  247.             lp -= ct;}
  248.         return (FALSE);
  249.     case CCHR|MTYPE:
  250.         c=*ep++;i1=*ep++&0xFF,i2=*ep++&0xFF;
  251.         while(*lp==c&&i1)lp++,i1--;
  252.         if(i1)return FALSE;
  253.         if(!i2||!lp[-1]) break;
  254.         if(i2==0xFF)i2=MAXBUF;
  255.         curlp=lp;
  256.         while(*lp++==c&&i2)i2--;
  257.         goto star;
  258.     case CCL|MTYPE:
  259.         tep=ep;ep+=32;
  260.         i1=*ep++&0xFF,i2=*ep++&0xFF;
  261.         do{ct=*lp++&0xff;
  262.            if(!(tep[ct>>3]&bits[ct&07]))break;
  263.            }while(--i1);
  264.         if(i1)return FALSE;
  265.         if(!i2||!lp[-1]) break;
  266.         if(i2==0xFF)i2=MAXBUF;
  267.         curlp=lp;
  268.         do{ct=*lp++&0xff;
  269.            if(!(tep[ct>>3]&bits[ct&07]))break;
  270.            }while(--i2);
  271.         goto star;
  272.     case CDOT|MTYPE:
  273.         i1=*ep++&0xFF,i2=*ep++&0xFF;
  274.         while(*lp&&i1)lp++,i1--;
  275.         if(i1)return FALSE;
  276.         if(!i2||!lp[-1]) break;
  277.         if(i2==0xFF)i2=MAXBUF;
  278.         curlp=lp;
  279.         while(*lp++&&i2)i2--;
  280.         goto star;
  281.       case CDOT | STAR:            /* match .* */
  282.         curlp = lp;            /* save closure start loc */
  283.         while (*lp++) ;            /* match anything */
  284.         goto star;            /* now look for followers */
  285.       case CCHR | STAR:            /* match <literal char>* */
  286.         curlp = lp;            /* save closure start loc */
  287.         while (*lp++ == *ep) ;        /* match many of that char */
  288.         ep++;                /* to start of next element */
  289.         goto star;            /* match it and followers */
  290.       case CCL | STAR:            /* match [...]* */
  291.         curlp = lp;            /* save closure set start loc */
  292.         do {ct = *lp++ & 0xFF;    /* match any in set */
  293.         } while (ep[ct>>3] & bits[ct & 07]);
  294.         ep += 32;            /* skip past the set */
  295.         goto star;            /* match followers */
  296.       star:        /* the recursion part of a * or + match */
  297.         if (--lp == curlp)break;    /* 0 matches */
  298.         if (*ep == CCHR) {c = ep[1];
  299.             do {if (*lp != c) continue;
  300.                 if (advance(lp, ep))return (TRUE);
  301.                 } while (lp-- > curlp);
  302.             return (FALSE);}
  303.         if (*ep == CBACK) {c = *(brastart[ep[1]]);
  304.             do {if (*lp != c)continue;
  305.                 if (advance(lp, ep))return (TRUE);
  306.                 } while (lp-- > curlp);
  307.             return (FALSE);}
  308.         do {
  309.             if (advance(lp, ep)) return (TRUE);
  310.             } while (lp-- > curlp);
  311.         return (FALSE);
  312.       default:ABORT2(REBAD,*--ep);}
  313.     bracend[0] = lp;        /* set second loc */
  314.     return (TRUE); }    /* wow we matched it */
  315.  
  316. static int substitute(ipc) sedcmd  *ipc;{ /* ptr to s command struct to do */
  317.         int repcnt=1, fcnt=ipc->flags.nthone;
  318.     if (match(ipc->u.lhs, 0))    /* if no match */
  319.         {if(fcnt<=1) dosub(ipc->rhs);}    /* perform it once */
  320.     else   return (FALSE);    /* command fails */
  321.     if (fcnt>1||ipc->flags.global)        /* if global flag enabled */
  322.         while (*bracend[0])        /* cycle through possibles */
  323.             if (match(ipc->u.lhs, 1))    /* found another */
  324.                {if(!fcnt||++repcnt==fcnt)dosub(ipc->rhs);
  325.                             if(fcnt==repcnt)
  326.                     if(!ipc->flags.global)break;
  327.                     else fcnt=0;}
  328.             else    break;            /* otherwise,done */
  329.     return !fcnt||fcnt==repcnt;}    /* we succeeded */
  330.  
  331. /* generate substituted right-hand side (of s command) */
  332. static void dosub(rhsbuf) char *rhsbuf;{/* uses linebuf, genbuf, spend */
  333.     register char  *lp, *sp, *rp;
  334.     int c,room=linebuf+MAXBUF-spend+bracend[0]-brastart[0];
  335.     /* copy linebuf to genbuf up to location  1 */
  336.     lp = linebuf;sp = genbuf;
  337.     while (lp < brastart[0])*sp++ = *lp++;
  338.     for (rp = rhsbuf;
  339.         ( --room>0) && ((c = *rp++) != 0)    /* v1.4 expanded */
  340.          ;)
  341.         if (c==ARGMARK && *rp>= '0' && *rp<MAXTAGS + '1'){c=*rp++ - '0';
  342.            if((room-=bracend[c]-brastart[c])<=0)break;
  343.            else   sp=place(sp,brastart[c], bracend[c]);}
  344.         else *sp++ = c;
  345.         if(room<=0)ABORT2(LTLMSG,lnum);
  346.     lp = bracend[0]; bracend[0]= linebuf+(sp-genbuf);
  347.     while ( (*sp++ = *lp++) != 0)  ;  /*copy rest of text*//* v1.1 */
  348.     lp = linebuf;    sp = genbuf;
  349.     while ( (*lp++ = *sp++) != 0) ;     /*copy the line back*//* v1.1 */
  350.     spend = lp - 1;}
  351.  
  352. /* place chars at *al1...*(al1 - 1) at asp... in genbuf[] */
  353. static char    *place(asp, al1, al2)  char *asp, *al1,*al2;{
  354.   while (al1 < al2) { *asp++ = *al1++;
  355.      if (asp >= genbuf + MAXBUF) ABORT2(LTLMSG,lnum);}
  356.   return (asp);}
  357.  
  358. /* write a hex dump expansion of *p1... to fp */
  359. static void listto(p1, fp) char *p1; FILE *fp; {char c;
  360.     while ( (c=*p1++) != 0)        /* v1.4 */
  361.         if (isprint(c)&&c!='\\')
  362.             putc(c, fp);    /* pass it through */
  363.         else {
  364.             putc('\\', fp);    /* emit a backslash */
  365.             switch (c) {
  366.               case '\\': putc('\\', fp); break;
  367.               case '\a': putc('a', fp); break;
  368.               case '\b': putc('b', fp); break;
  369.               case  27 : putc('e', fp); break; /*ESC*/
  370.               case '\f': putc('f', fp); break;
  371.               case '\n': putc('n', fp); break;
  372.               case '\r': putc('r', fp); break;
  373.               case '\t': putc('t', fp); break;
  374.               case '\v': putc('v', fp); break;
  375.                 default: fprintf(fp, "x%02x", c & 0xFF);}}
  376.     putc('\n', fp);}
  377.  
  378. /* execute compiled command pointed at by ipc */
  379. static void    command(ipc) sedcmd *ipc;{
  380.     static int     didsub;        /* true if last s succeeded */
  381.     static char     holdsp[MAXHOLD]; /* the hold space */
  382.     static char    *hspend = holdsp;/* hold space end pointer */
  383.     register char    *p1, *p2;     /* temp pointers*/
  384.     char            *execp;
  385.     switch (ipc->command) {
  386.            case ACMD:            /* append */
  387.             *aptr++ = ipc;
  388.             if (aptr >= appends + MAXAPPENDS) ABORT2(APPERR,lnum);
  389.             *aptr = 0;
  390.             break;
  391.            case CCMD:            /* change pattern space */
  392.             delete = TRUE;
  393.             if (!ipc->flags.inrange || lastline)
  394.                 printf("%s\n", ipc->u.lhs);
  395.             break;
  396.            case DCMD:            /* delete pattern space */
  397.             delete++;
  398.             break;
  399.            case CDCMD:        /* delete a line in hold space */
  400.             p1 = linebuf;delete++;
  401.             while (*p1&&*p1 != '\n') p1++;
  402.                         if(!*p1++) return;
  403.             Copy(linebuf,p1,spend);
  404.             cdswitch=TRUE;
  405.             break;
  406.            case EQCMD:            /* show current line number */
  407.             fprintf(stdout, "%ld\n", lnum);
  408.             break;
  409.            case GCMD:        /* copy hold space to pattern space */
  410.             Copy(linebuf,holdsp,spend);
  411.             break;
  412.            case CGCMD:    /* append hold space to pattern space */
  413.             if(spend!=linebuf) *spend++ = '\n';
  414.             if(spend+(hspend-holdsp)>linebuf+MAXBUF)
  415.                   ABORT2(APPLNG,lnum);
  416.             Copy(spend,holdsp,spend);
  417.             break;
  418.            case HCMD:        /* copy pattern space to hold space */
  419.             Copy(holdsp,linebuf,hspend);
  420.             break;
  421.            case CHCMD:    /* append pattern space to hold space */
  422.             if(hspend!=holdsp) *hspend++='\n';
  423.             if(hspend+(spend-linebuf)>holdsp+MAXBUF)
  424.                   ABORT2(APPLNG,lnum);
  425.             Copy(hspend,linebuf,hspend);
  426.             break;
  427.            case ICMD:            /* insert text */
  428.             printf("%s\n", ipc->u.lhs);
  429.             break;
  430.            case BRCMD:            /* grouping cammand */
  431.             {sedcmd *a=ipc; while(++a<ipc->u.link)a->flags.inrange=0;}
  432.            case BCMD:     /*branch to label command*/
  433.                         jump = TRUE;
  434.             break;
  435.            case LCMD:            /* list text */
  436.             listto(linebuf,(ipc->fout != NULL)?ipc->fout : stdout);
  437.             break;
  438.            case NCMD: /*read next line into pattern space*/
  439.            case CNCMD: /*append next line to pattern space*/
  440.             if(!pending){
  441.                 if(ipc->command==NCMD){
  442.                    if(!nflag)puts(linebuf);
  443.                    spend=linebuf;}
  444.                 else  *spend++='\n';
  445.                 if(aptr>appends) readout();}/*do any pending a,r*/
  446.             *spend=0;
  447.             if(!(execp=getline(spend)))
  448.                 pending=lastline?NULL:ipc,delete=TRUE;
  449.             else pending=NULL,spend=execp;
  450.             if(spend>linebuf+MAXBUF)ABORT2(APPLNG,lnum);
  451.             break;
  452.            case PCMD:        /* print pattern space */
  453.             puts(linebuf);
  454.             break;
  455.            case CPCMD:    /* print one line from pattern space */
  456.       cpcom:        /* so s command can jump here */
  457.             for (p1 = linebuf; *p1 != '\n' && *p1 != '\0';)
  458.                   putc(*p1++, stdout);
  459.             putc('\n', stdout);
  460.             break;
  461.            case QCMD:    /* quit the stream editor */
  462.             if (!nflag)
  463.             puts(linebuf);    /* flush out the current line */
  464.             if (aptr > appends)
  465.             readout();    /* do any pending a and r commands */
  466.             exit(0);
  467.            case RCMD:        /* read a file into the stream */
  468.             *aptr++ = ipc;
  469.             if (aptr >= appends + MAXAPPENDS)ABORT2(READERR,lnum);
  470.             *aptr = 0;
  471.             break;
  472.            case SCMD:        /* substitute RE */
  473.             if(didsub=substitute(ipc)){
  474.             if(ipc->fout) fprintf(ipc->fout,"%s\n",linebuf);
  475.             if(ipc->flags.print==1) puts(linebuf);
  476.             else if(ipc->flags.print) goto cpcom;}
  477.             break;
  478.            case TCMD:  /* branch on last s successful */
  479.            case CTCMD: /* branch on last s failed */
  480.             jump =(didsub==(ipc->command==TCMD));
  481.             didsub = FALSE;/*reset after test*/
  482.             break;
  483.            case CWCMD:    /* write one line from pattern space */
  484.             for (p1 = linebuf; *p1 != '\n' && *p1 != '\0';)
  485.             putc(*p1++, ipc->fout);
  486.             putc('\n', ipc->fout);
  487.             break;
  488.            case WCMD:    /* write pattern space to file */
  489.             fprintf(ipc->fout, "%s\n", linebuf);
  490.             break;
  491.            case XCMD:    /* exchange pattern and hold spaces */
  492.             Copy(genbuf,linebuf,spend);
  493.             Copy(linebuf,holdsp,spend);
  494.             Copy(holdsp,genbuf,hspend);
  495.             break;
  496.            case YCMD:
  497.             p1 = linebuf;p2 = ipc->u.lhs;
  498.             while(*p1){*p1=p2[(*p1)&0xFF]; p1++;}
  499.             break;}}
  500.  
  501. /* get next line of text to be filtered */
  502. static char *getline(buf) char *buf;/* where to put line*/{
  503.   int temp;
  504.   if (gets(buf) != NULL) {/*hh 20*/
  505.      lnum++;    /* note that we got another line */
  506.      while (*buf++) ;        /* find the end of the input */
  507.      if((temp=getc(stdin))==EOF)/*hh 20*/
  508.             lastline=(eargc==0);
  509.      else ungetc(temp,stdin);
  510.      return (--buf);}    /* return ptr to terminating null */
  511.   else  if (eargc == 0)    lastline = TRUE;  /* if no more args this is it */
  512.   return NULL;}
  513.  
  514. /* return TRUE if *a... == *b... for count chars, FALSE otherwise */
  515. static int    smemcmp(a, b, count) register char  *a, *b;int count;{
  516.     while (count--)                /* look at count characters */
  517.         if (*a++ != *b++)        /* if any are nonequal   */
  518.             return (FALSE);        /* return FALSE for false */
  519.     return (TRUE);}                /* compare succeeded */
  520.  
  521. /* write file indicated by r command to output */
  522. static void readout() {
  523.     register int    t;            /* hold input char or EOF */
  524.     FILE           *fi;        /* ptr to file to be read */
  525.     aptr = appends - 1;    /* arrange for pre-increment to work right */
  526.     while (*++aptr)
  527.         if ((*aptr)->command == ACMD)    /* process "a" cmd */
  528.             printf("%s\n", (*aptr)->u.lhs);
  529.     else {                /* process "r" cmd */
  530.         if((fi=fopen((*aptr)->u.lhs,"rt"))==NULL)
  531.              ABORT2(FILEBAD,(*aptr)->u.lhs);
  532.         while ((t = getc(fi)) != EOF)
  533.             putc((char) t, stdout);
  534.         fclose(fi);}
  535.     aptr = appends;        /* reset the append ptr */
  536.     *aptr = 0;}
  537.  
  538. /* sedexec.c ends here */
  539.